package com.group.itms.routes.activities;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.group.itms.routes.R;
import com.group.itms.routes.data.BObject;
import com.group.itms.routes.data.ObjectGps;
import com.group.itms.routes.data.ObjectMap;
import com.group.itms.routes.data.ObjectType;
import com.group.itms.routes.map.Bounds;
import com.group.itms.routes.map.GoogleMapWrapper;
import com.group.itms.routes.map.Layer;
import com.group.itms.routes.map.Layer.Type;
import com.group.itms.routes.map.Map;
import com.group.itms.routes.map.Map.MapType;
import com.group.itms.routes.map.Marker;
import com.group.itms.routes.map.OfflineMap;
import com.group.itms.routes.map.OfflineMapView;
import com.group.itms.routes.map.OfflineMapWrapper;
import com.group.itms.routes.map.PointD;
import com.group.itms.routes.map.Projection;

public class MapActivity extends BaseActivity {

	private static final String TAG = "MapActivity";
	public static final String REQUEST_OFFLINE = "request_offline";
	public static final String MAP_TYPE = "map_type";

	private Menu mMenu;

	private BObject mObject;
	private Map mMap;
	private boolean mRecheckGoogleMap;

	private List<Layer> mLayers;
	private int mCurrentMapType = 2;

	private DrawerLayout mDrawerLayout;
	private ActionBarDrawerToggle mDrawerToggle;

	public static Intent getIntent(Context ctx, int objId) {
		return getIntent(ctx, objId, false);
	}

	public static Intent getIntent(Context ctx, int objId, boolean offline) {
		Intent intent = new Intent(ctx, MapActivity.class);
		intent.putExtra(OBJECT_ID, objId);
		intent.putExtra(REQUEST_OFFLINE, offline);
		return intent;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mDrawerLayout = (DrawerLayout) getLayoutInflater().inflate(
				R.layout.activity_map_with_drawer, null);
		setContentView(mDrawerLayout);
		setContentView(mDrawerLayout);

		if (savedInstanceState != null
				&& savedInstanceState.getInt(MAP_TYPE, -1) != -1)
			mCurrentMapType = savedInstanceState.getInt(MAP_TYPE);

		boolean mOfflineRequested = getIntent().getBooleanExtra(
				REQUEST_OFFLINE, false);
		int objId = getIntent().getIntExtra(OBJECT_ID, -1);
		mObject = getObject(objId);
		if (hasConnection() && !mOfflineRequested) {
			setupGoogleMap();
		} else {
			if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
				setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
				return;
			}
			setupOfflineMap();
		}
		setUpDrawer();
		mLayers = getAllLayers();
		mMap.addLayers(mLayers);
	}

	private void setUpDrawer() {
		ArrayAdapter<String> layerDrawerAdapter = new ArrayAdapter<String>(
				this, android.R.layout.simple_list_item_multiple_choice,
				Arrays.asList("Points", "Tasks", "Routes"));

		final ListView layerDrawerListView = (ListView) findViewById(R.id.layer_drawer);
		layerDrawerListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
		layerDrawerListView.setAdapter(layerDrawerAdapter);
		layerDrawerListView.setItemChecked(0, true);
		layerDrawerListView.setItemChecked(1, true);
		layerDrawerListView.setItemChecked(2, true);
		layerDrawerListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				boolean checked = layerDrawerListView.isItemChecked(position);
				layerDrawerListView.setItemChecked(position, checked);
				mMap.setLayerTypeVisibility(Type.values()[position], checked);
			}
		});

		mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
				R.drawable.ic_drawer, R.string.open_drawer,
				R.string.closed_drawer) {
			@Override
			public void onDrawerClosed(View drawerView) {
				super.onDrawerClosed(drawerView);
				getSupportActionBar().setTitle(mObject.getName());
			}

			@Override
			public void onDrawerOpened(View drawerView) {
				super.onDrawerOpened(drawerView);
				getSupportActionBar().setTitle("Choose objects to show");
			}
		};
		mDrawerLayout.setDrawerListener(mDrawerToggle);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getSupportMenuInflater().inflate(R.menu.menu_map_activity, menu);
		mMenu = menu;

		if (mMap != null && (mMap instanceof OfflineMapWrapper)) {
			if (hasConnection())
				mMenu.findItem(R.id.offlineOnlineMap).setVisible(true);
			else
				mMenu.findItem(R.id.offlineOnlineMap).setVisible(false);
			mMenu.findItem(R.id.Terrain).setVisible(false);
			mMenu.findItem(R.id.Normal).setVisible(false);
			mMenu.findItem(R.id.Hybrid).setVisible(false);
			mMenu.findItem(R.id.Satellite).setVisible(false);
		}
		return super.onCreateOptionsMenu(menu);
	}
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		mDrawerToggle.onConfigurationChanged(newConfig);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item != null && item.getItemId() == android.R.id.home && mDrawerToggle.isDrawerIndicatorEnabled()) {
            if (mDrawerLayout.isDrawerVisible(GravityCompat.START)) {
                mDrawerLayout.closeDrawer(GravityCompat.START);
            } else {
                mDrawerLayout.openDrawer(GravityCompat.START);
            }
            return true;
        }
		switch (item.getItemId()) {
		case R.id.Hybrid:
			mMap.setMapType(MapType.Hybrid);
			mCurrentMapType = MapType.Hybrid.ordinal();
			break;
		case R.id.Normal:
			mMap.setMapType(MapType.Normal);
			mCurrentMapType = MapType.Normal.ordinal();
			break;
		case R.id.Satellite:
			mMap.setMapType(MapType.Stallite);
			mCurrentMapType = MapType.Stallite.ordinal();
			break;
		case R.id.Terrain:
			mMap.setMapType(MapType.Terrain);
			mCurrentMapType = MapType.Terrain.ordinal();
			break;
		case R.id.offlineOnlineMap:
			if (mMap instanceof GoogleMapWrapper) {
				startActivity(getIntent(this, mObject.getId(), true));
			}
			break;
		case R.id.goToRoutes:
			mMap.goToRoutes();
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);
		mDrawerToggle.syncState();
	}
	
	private void setCurrentLocationOnMap() {
		mMap.setMyLocation();
	}

	private List<Layer> getAllLayers() {
		List<Layer> layers;
		if (mObject.is(ObjectType.LOCATION)) {
			List<BObject> routes = mObject.getChildrenRoutes();
			layers = getLayersFromRouteList(routes);
		} else if (mObject.is(ObjectType.ROUTE)) {
			layers = getLayersFromRoute(mObject);
		} else { // point or task
			Layer l = new Layer();
			Marker m;
			if (mObject.is(ObjectType.INF_POINT)) {
				m = getMarker(mObject, R.drawable.ic_point);
				l.setType(Type.POINT);
				l.setName(mObject.getIndName());
			} else {
				m = getMarker(mObject, R.drawable.ic_task);
				l.setType(Type.TASK);
				l.setName(mObject.getIndName());
			}
			l.addMarker(m);
			layers = Arrays.asList(l);
		}
		return layers;
	}

	private List<Layer> getLayersFromRouteList(List<BObject> routes) {
		List<Layer> rLayers = new ArrayList<Layer>();
		for (BObject r : routes) {
			List<Layer> layers = getLayersFromRoute(r);
			rLayers.addAll(layers);
		}
		return rLayers;
	}

	private List<Layer> getLayersFromRoute(BObject r) {
		List<Layer> layers = new ArrayList<Layer>();
		List<ObjectGps> gpsObjects = r.getGpsObjects();
		Layer routeLayer = new Layer();
		routeLayer.setType(Type.ROUTE);
		routeLayer.setName(r.getIndName());
		for (ObjectGps gps : gpsObjects) {
			Marker m = new Marker();
			m.setObject(gps.getObject());
			m.setLocation(new PointD(gps.getX(), gps.getY()));
			routeLayer.addMarker(m);
		}
		layers.add(routeLayer);

		List<BObject> points = r.getChildrenPoints();
		List<BObject> task = r.getChildrenTasks();
		Layer lp = getLayer(points, R.drawable.ic_point);
		Layer lt = getLayer(task, R.drawable.ic_task);
		layers.add(lp);
		layers.add(lt);
		return layers;
	}

	private Layer getLayer(List<BObject> objects, int icId) {
		Layer layer = new Layer();
		layer.setType(icId == R.drawable.ic_point ? Type.POINT : Type.TASK);
		// layer.setId(id);
		for (BObject obj : objects) {
			Marker m = getMarker(obj, icId);
			if (m != null) {
				layer.addMarker(m);
			}
		}
		return layer;
	}

	private Marker getMarker(BObject object, int icId) {
		List<ObjectGps> gpts = object.getGpsObjects();
		if (gpts.size() > 0) {
			ObjectGps og = gpts.get(0);
			Marker m = new Marker();
			m.setObject(object);
			m.setIcon(getBitmap(icId));
			m.setLocation(new PointD(og.getX(), og.getY()));
			return m;
		}
		return null;
	}

	private void setupOfflineMap() {
		mMap = new OfflineMapWrapper(this);
		ObjectMap om;
		try {
			om = getHelper().getObjectMapDao()
					.queryForEq(ObjectMap.OBJECT, mObject).get(0);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
		byte[] mapBytes = om.getMap();
		Bitmap b = BitmapFactory.decodeByteArray(mapBytes, 0, mapBytes.length);
		OfflineMapView omv = new OfflineMapView(this);
		omv.setMapImage(b);
		OfflineMap offlnMap = omv.getOfflineMap();
		offlnMap.setProjection(new Projection(getBounds(om)));
		mMap.setMapInternal(offlnMap);
		FrameLayout container = (FrameLayout) findViewById(R.id.content);
		container.addView(omv);
	}

	private Bounds getBounds(ObjectMap om) {
		Bounds b = new Bounds();
		b.setLeftDowonX(om.getX2());
		b.setLeftDowonY(om.getY2());
		b.setRightUpX(om.getX4());
		b.setRightUpY(om.getY4());

		// b.setLeftDowonX(41.473312);
		// b.setLeftDowonY(44.491786);
		// b.setRightUpX(41.495153);
		// b.setRightUpY(44.532729);
		return b;
	}

	private void setupGoogleMap() {
		mMap = new GoogleMapWrapper(this);
		ObjectMap om;
		try {
			om = getHelper().getObjectMapDao()
					.queryForEq(ObjectMap.OBJECT, mObject).get(0);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
		mMap.setBounds(getBounds(om));
		FragmentManager fm = getSupportFragmentManager();
		SupportMapFragment mf = (SupportMapFragment) fm
				.findFragmentById(R.id.content);
		if (mf == null) {
			mf = SupportMapFragment.newInstance();
			fm.beginTransaction().add(R.id.content, mf).commit();
		}
		if (!doSetupGoogleMap()) {
			mRecheckGoogleMap = true;
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (mRecheckGoogleMap) {
			if (doSetupGoogleMap()) {
				mRecheckGoogleMap = false;
			} else {
				// TODO report issue
			}
		}
	}

	private boolean doSetupGoogleMap() {
		GoogleMap gMap = getGoogleMap();
		if (gMap != null) {
			gMap.setMyLocationEnabled(true);
			mMap.setMapInternal(gMap);
			mMap.setMapType(MapType.values()[mCurrentMapType]);
			mMap.addLayers(mLayers);
			return true;
		}
		return false;
	}

	private GoogleMap getGoogleMap() {
		SupportMapFragment mf = getMapFragment();
		if (mf == null) {
			return null;
		}
		return mf.getMap();
	}

	private SupportMapFragment getMapFragment() {
		return (SupportMapFragment) getSupportFragmentManager()
				.findFragmentById(R.id.content);
	}

	private Bitmap getBitmap(int id) {
		return BitmapFactory.decodeResource(getResources(), id);
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putInt(MAP_TYPE, mCurrentMapType);
	}

	@Override
	protected String getTag() {
		return TAG;
	}

}
